// import com.alibaba.druid.sql.ast.*;
// import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor;
// import com.alibaba.druid.sql.visitor.SQLASTVisitor;

// import java.util.ArrayList;
// import java.util.List;

#include "OracleAnalytic.h"
#include "../../visitor/OracleASTVisitor.h"
#include "../../../../visitor/SQLASTVisitor.h"
#include "OracleAnalyticWindowing.h"
#include "../../../../../utils/listAddAll.h"
#include "../../../../../utils/listTran.h"
#include "../../../../ast/SQLOrderBy.h"

OracleAnalytic::OracleAnalytic()
{
}

// @Override
void OracleAnalytic::accept0(SQLASTVisitor_ptr visitor)
{
  this->accept0(std::dynamic_pointer_cast<OracleASTVisitor>(visitor));
}

void OracleAnalytic::accept0(OracleASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(OracleAnalytic)))
  {
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(this->partitionBy);
    acceptChild(visitor, tmp1);
    acceptChild(visitor, this->orderBy);
    acceptChild(visitor, this->windowing);
  }
  visitor->endVisit(SharedObject(OracleAnalytic));
}

// @Override
SQLObject_list_ptr OracleAnalytic::getChildren()
{
  SQLObject_list_ptr children = std::make_shared<std::list<SQLObject_ptr>>();
  // children.addAll(this->partitionBy);
  Utils::ListAddAll<SQLExpr, SQLObject>(this->partitionBy, children);
  if (this->orderBy != nullptr)
  {
    children->push_back(orderBy);
  }
  if (this->windowing != nullptr)
  {
    children->push_back(windowing);
  }
  return children;
}

OracleAnalyticWindowing_ptr OracleAnalytic::getWindowing()
{
  return this->windowing;
}

SQLObject_ptr OracleAnalytic::clone()
{
  SQLObject_ptr clone_tmp = std::shared_ptr<OracleAnalytic>(new OracleAnalytic());
  std::shared_ptr<OracleAnalytic> x = std::dynamic_pointer_cast<OracleAnalytic>(clone_tmp);
  // OracleAnalytic x = new OracleAnalytic();

  SQLOver::cloneTo(x);

  if (windowing != nullptr)
  {
    x->setWindowing(std::dynamic_pointer_cast<OracleAnalyticWindowing>(windowing->clone()));
  }

  return x;
}

void OracleAnalytic::setWindowing(OracleAnalyticWindowing_ptr x)
{
  if (x != nullptr)
  {
    x->setParent(SharedObject(OracleAnalytic));
  }
  this->windowing = x;
}

SQLDataType_ptr OracleAnalytic::computeDataType()
{
  return nullptr;
}

// @Override
BOOL_ptr OracleAnalytic::replace(SQLExpr_ptr expr, SQLExpr_ptr target)
{
  auto it_partitionBy = partitionBy->begin();
  for (int i = 0; i < partitionBy->size(); i++)
  {
    std::advance(it_partitionBy, i);
    if (*it_partitionBy == expr)
    {
      *it_partitionBy = target;
      return BOOL::TRUE;
    }
  }

  return BOOL::FALSE;
}
